package xin.marcher.wind.migrate.config;

import com.baomidou.mybatisplus.core.toolkit.CollectionUtils;
import lombok.extern.slf4j.Slf4j;
import org.apache.ibatis.session.SqlSession;
import org.mybatis.spring.SqlSessionFactoryBean;
import org.mybatis.spring.SqlSessionTemplate;
import org.mybatis.spring.SqlSessionUtils;
import org.springframework.stereotype.Component;
import xin.marcher.wind.migrate.domain.entity.ScrollDbConfigDO;
import xin.marcher.wind.migrate.domain.entity.ScrollDomainDO;
import xin.marcher.wind.migrate.domain.entity.ScrollShardConfigDO;
import xin.marcher.wind.migrate.service.MigrateConfigService;
import xin.marcher.wind.migrate.sharding.DataSourceProperties;
import xin.marcher.wind.migrate.sharding.MigrateDataSourceProperties;
import xin.marcher.wind.migrate.sharding.TableRuleProperties;

import javax.annotation.PostConstruct;
import javax.annotation.Resource;
import javax.sql.DataSource;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

@Slf4j
@Component
public class ScrollDataSourceConfig extends AbstractDataSourceConfig {

    /**
     * 存储需要进行数据迁移的数据源对象
     */
    private Map<String, SqlSessionTemplate> dataSourceMap = new HashMap<>();

    @Resource
    private MigrateConfigService migrateConfigService;

    private static final String driverClassName = "com.mysql.cj.jdbc.Driver";

    private static final String split = "&";

    /**
     * 初始化加载目前需要进行数据迁移的相关配置
     */
    @PostConstruct
    public void initMigrateDateSource() throws Exception {
        // 获取所有的需要迁移的配置 系统域对象
        List<ScrollDomainDO> scrollDomainDOList = migrateConfigService.queryScrollDomainList();

        // 按系统业务，加载当前的数据源信息
        for (ScrollDomainDO scrollDomainDO : scrollDomainDOList) {
            // 当前系统对应的数据源信息
            List<ScrollDbConfigDO> scrollDbConfigDOList = migrateConfigService.queryScrollDbConfigList(scrollDomainDO.getId());
            // 当前数据源对应的分区策略
            List<ScrollShardConfigDO> scrollShardConfigDOS = migrateConfigService.queryScrollShardConfigList(scrollDomainDO.getId());

            MigrateDataSourceProperties migrateDataSourceProperties = new MigrateDataSourceProperties();
            migrateDataSourceProperties.setDataSources(buildDataSourceConfig(scrollDbConfigDOList));
            migrateDataSourceProperties.setTableRules(buildTableRuleConfig(scrollShardConfigDOS));
            migrateDataSourceProperties.setSqlshow(scrollDomainDO.getSqlshow() != 0);
            migrateDataSourceProperties.setTableNum(scrollDomainDO.getTableNum());
            // 加载数据源
            DataSource dataSource = buildDataSource(migrateDataSourceProperties);
            log.info("当前正在加载:【" + scrollDomainDO.getDomain() + "】的数据源：" + "加载数据源数量：" + scrollDbConfigDOList.size());
            SqlSessionFactoryBean sqlSessionFactory = new SqlSessionFactoryBean();
            sqlSessionFactory.setDataSource(dataSource);

            // 缓存对应的数据源信息
            dataSourceMap.put(scrollDomainDO.getDomain() + split + scrollDomainDO.getDataSourceType(), new SqlSessionTemplate(sqlSessionFactory.getObject()));
        }
    }

    /**
     * 获取数据源
     *
     * @param domain         渠道系统应用名称
     * @param dataSourceType 数据源类型
     * @return
     */
    public SqlSession getSqlSession(String domain, Integer dataSourceType) {
        try {
            SqlSessionTemplate sqlSessionTemplate = dataSourceMap.get(domain + split + dataSourceType);

            return SqlSessionUtils.getSqlSession(sqlSessionTemplate.getSqlSessionFactory(),
                    sqlSessionTemplate.getExecutorType(), sqlSessionTemplate.getPersistenceExceptionTranslator());
        } catch (Exception e) {
            log.error("加载数据源对应连接池失败", e);
        }
        return null;
    }

    /**
     * 关闭 sqlSession
     *
     * @param session
     */
    public void closeSqlSession(SqlSession session, String domain, Integer dataSourceType) {
        SqlSessionTemplate sqlSessionTemplate = dataSourceMap.get(domain + split + dataSourceType);
        SqlSessionUtils.closeSqlSession(session, sqlSessionTemplate.getSqlSessionFactory());
    }

    /**
     * 将数据配置封装为原始的数据源配置类
     *
     * @param scrollDbConfigDOList
     * @return
     */
    private List<DataSourceProperties> buildDataSourceConfig(List<ScrollDbConfigDO> scrollDbConfigDOList) {
        List<DataSourceProperties> dataSourcePropertiesList = new ArrayList<>();
        // 填充数据源配置
        for (ScrollDbConfigDO scrollDbConfigDO : scrollDbConfigDOList) {
            DataSourceProperties dataSourceProperties = new DataSourceProperties();
            dataSourceProperties.setDriverClassName(driverClassName);
            dataSourceProperties.setUrl(scrollDbConfigDO.getJdbcUrl());
            dataSourceProperties.setPassword(scrollDbConfigDO.getJdbcPassword());
            dataSourceProperties.setUsername(scrollDbConfigDO.getJdbcUserName());
            dataSourcePropertiesList.add(dataSourceProperties);
        }
        return dataSourcePropertiesList;
    }

    /**
     * 加载当前数据源对应的分区分表策略
     *
     * @param scrollShardConfigDOList
     * @return
     */
    private List<TableRuleProperties> buildTableRuleConfig(List<ScrollShardConfigDO> scrollShardConfigDOList) {
        List<TableRuleProperties> tableRulePropertiesList = new ArrayList<>();
        if (CollectionUtils.isNotEmpty(scrollShardConfigDOList)) {
            for (ScrollShardConfigDO scrollShardConfigDO : scrollShardConfigDOList) {
                TableRuleProperties tableRuleProperties = new TableRuleProperties();
                tableRuleProperties.setDbShardingAlgorithm(scrollShardConfigDO.getDbShardingAlgorithm());
                tableRuleProperties.setDbShardingColumns(scrollShardConfigDO.getDbShardingColumns());
                tableRuleProperties.setLogicTable(scrollShardConfigDO.getLogicModel());
                tableRuleProperties.setTableShardingAlgorithm(scrollShardConfigDO.getTableShardingAlgorithm());
                tableRuleProperties.setTableShardingColumns(scrollShardConfigDO.getTableShardingColumns());
                tableRulePropertiesList.add(tableRuleProperties);
            }
        }
        return tableRulePropertiesList;
    }

}
